package main

import "fmt"

// Environment represents a variable binding environment with lexical scoping
type Environment struct {
	bindings map[string]*Value
	parent   *Environment
}

// NewEnvironment creates a new environment with an optional parent
func NewEnvironment(parent *Environment) *Environment {
	return &Environment{
		bindings: make(map[string]*Value),
		parent:   parent,
	}
}

// NewGlobalEnvironment creates the global environment with built-in functions
func NewGlobalEnvironment() *Environment {
	env := NewEnvironment(nil)

	// Add built-in arithmetic functions
	env.Define("+", NewBuiltin(builtinAdd))
	env.Define("-", NewBuiltin(builtinSub))
	env.Define("*", NewBuiltin(builtinMul))
	env.Define("/", NewBuiltin(builtinDiv))
	env.Define("abs", NewBuiltin(builtinAbs)) // Add abs function
	env.Define("remainder", NewBuiltin(builtinRemainder))
	env.Define("modulo", NewBuiltin(builtinModulo))

	// Add built-in comparison functions
	env.Define("=", NewBuiltin(builtinEqual))
	env.Define("<", NewBuiltin(builtinLess))
	env.Define(">", NewBuiltin(builtinGreater))
	env.Define("<=", NewBuiltin(builtinLessEqual))
	env.Define(">=", NewBuiltin(builtinGreaterEqual))

	// Add built-in logical functions
	env.Define("and", NewBuiltin(builtinAnd))
	env.Define("or", NewBuiltin(builtinOr))
	env.Define("not", NewBuiltin(builtinNot))

	// Add built-in list functions
	env.Define("cons", NewBuiltin(builtinCons))
	env.Define("car", NewBuiltin(builtinCar))
	env.Define("cdr", NewBuiltin(builtinCdr))
	env.Define("list", NewBuiltin(builtinList))
	env.Define("null?", NewBuiltin(builtinNullp))
	env.Define("eq?", NewBuiltin(builtinEqp))
	env.Define("eqv?", NewBuiltin(builtinEqvp)) // 添加eqv?
	env.Define("equal?", NewBuiltin(builtinEqualp))
	env.Define("pair?", NewBuiltin(builtinPairp))

	// Add file operations
	env.Define("load", NewBuiltin(builtinLoad))
	env.Define("newline", NewBuiltin(builtinNewline))

	// Add utility functions
	env.Define("error", NewBuiltin(builtinError))
	env.Define("number?", NewBuiltin(builtinNumberp))
	env.Define("exact-nonnegative-integer?", NewBuiltin(builtinExactNonnegativeIntegerp))
	// Add number sign checking functions
	env.Define("negative?", NewBuiltin(builtinNegativep))
	env.Define("positive?", NewBuiltin(builtinPositivep))
	env.Define("zero?", NewBuiltin(builtinZerop))
	// Add numeric truncation and rounding functions
	env.Define("floor", NewBuiltin(builtinFloor))
	env.Define("ceiling", NewBuiltin(builtinCeiling))
	env.Define("truncate", NewBuiltin(builtinTruncate))
	env.Define("round", NewBuiltin(builtinRound))
	// Add max, min, and quotient procedures
	env.Define("max", NewBuiltin(builtinMax))
	env.Define("min", NewBuiltin(builtinMin))
	env.Define("quotient", NewBuiltin(builtinQuotient))
	// Add odd?, even?, gcd, and lcm procedures
	env.Define("odd?", NewBuiltin(builtinOddp))
	env.Define("even?", NewBuiltin(builtinEvenp))
	env.Define("gcd", NewBuiltin(builtinGcd))
	env.Define("lcm", NewBuiltin(builtinLcm))

	// Add mutable list operations
	env.Define("set-car!", NewBuiltin(builtinSetCar))
	env.Define("set-cdr!", NewBuiltin(builtinSetCdr))
	// Add list manipulation functions
	env.Define("append", NewBuiltin(builtinAppend))
	env.Define("reverse", NewBuiltin(builtinReverse))
	env.Define("for-each", NewBuiltin(builtinForEach))
	// Define R4RS section 6.3 list procedures
	env.Define("list?", NewBuiltin(builtinListp))
	env.Define("length", NewBuiltin(builtinLength))
	env.Define("memq", NewBuiltin(builtinMemq))
	env.Define("memv", NewBuiltin(builtinMemv))
	env.Define("member", NewBuiltin(builtinMember))
	env.Define("assq", NewBuiltin(builtinAssq))
	env.Define("assv", NewBuiltin(builtinAssv))
	env.Define("assoc", NewBuiltin(builtinAssoc))

	// Add boolean, symbol, string, char, exact?, and inexact? predicates
	env.Define("boolean?", NewBuiltin(builtinBooleanp))
	env.Define("symbol?", NewBuiltin(builtinSymbolp))
	env.Define("string?", NewBuiltin(builtinStringp))
	env.Define("char?", NewBuiltin(builtinCharp))
	env.Define("exact?", NewBuiltin(builtinExactp))
	env.Define("inexact?", NewBuiltin(builtinInexactp))

	// Add character procedures (R4RS section 6.6)
	env.Define("char=?", NewBuiltin(builtinCharEqualp))
	env.Define("char<?", NewBuiltin(builtinCharLessp))
	env.Define("char>?", NewBuiltin(builtinCharGreaterp))
	env.Define("char<=?", NewBuiltin(builtinCharLessEqualp))
	env.Define("char>=?", NewBuiltin(builtinCharGreaterEqualp))
	env.Define("char-ci=?", NewBuiltin(builtinCharCiEqualp))
	env.Define("char-ci<?", NewBuiltin(builtinCharCiLessp))
	env.Define("char-ci>?", NewBuiltin(builtinCharCiGreaterp))
	env.Define("char-ci<=?", NewBuiltin(builtinCharCiLessEqualp))
	env.Define("char-ci>=?", NewBuiltin(builtinCharCiGreaterEqualp))
	env.Define("char-alphabetic?", NewBuiltin(builtinCharAlphabeticp))
	env.Define("char-numeric?", NewBuiltin(builtinCharNumericp))
	env.Define("char-whitespace?", NewBuiltin(builtinCharWhitespacep))
	env.Define("char-upper-case?", NewBuiltin(builtinCharUpperCasep))
	env.Define("char-lower-case?", NewBuiltin(builtinCharLowerCasep))
	env.Define("char->integer", NewBuiltin(builtinCharToInteger))
	env.Define("integer->char", NewBuiltin(builtinIntegerToChar))
	env.Define("char-upcase", NewBuiltin(builtinCharUpcase))
	env.Define("char-downcase", NewBuiltin(builtinCharDowncase))

	// Add essential procedures
	env.Define("procedure?", NewBuiltin(builtinProcedurep))
	env.Define("apply", NewBuiltin(builtinApply))
	env.Define("map", NewBuiltin(builtinMap))

	// Add I/O procedures
	env.Define("read", NewBuiltin(builtinRead))
	env.Define("write", NewBuiltin(builtinWrite))
	env.Define("display", NewBuiltin(builtinDisplay))
	env.Define("read-char", NewBuiltin(builtinReadChar))
	env.Define("write-char", NewBuiltin(builtinWriteChar))
	env.Define("newline", NewBuiltin(builtinNewline))
	env.Define("eof-object?", NewBuiltin(builtinEofObjectp))
    
	// Add call-with-current-continuation
	env.Define("call-with-current-continuation", NewBuiltin(builtinCallWithCurrentContinuation))
	env.Define("call/cc", NewBuiltin(builtinCallWithCurrentContinuation))

	// Add string procedures (R4RS section 6.7)
	env.Define("make-string", NewBuiltin(builtinMakeString))
	env.Define("string", NewBuiltin(builtinString))
	env.Define("string-length", NewBuiltin(builtinStringLength))
	env.Define("string-ref", NewBuiltin(builtinStringRef))
	env.Define("string-set!", NewBuiltin(builtinStringSet))
	env.Define("string=?", NewBuiltin(builtinStringEqual))
	env.Define("string-ci=?", NewBuiltin(builtinStringCiEqual))
	env.Define("string<?", NewBuiltin(builtinStringLess))
	env.Define("string>?", NewBuiltin(builtinStringGreater))
	env.Define("string<=?", NewBuiltin(builtinStringLessEqual))
	env.Define("string>=?", NewBuiltin(builtinStringGreaterEqual))
	env.Define("string-ci<?", NewBuiltin(builtinStringCiLess))
	env.Define("string-ci>?", NewBuiltin(builtinStringCiGreater))
	env.Define("string-ci<=?", NewBuiltin(builtinStringCiLessEqual))
	env.Define("string-ci>=?", NewBuiltin(builtinStringCiGreaterEqual))
	env.Define("substring", NewBuiltin(builtinSubstring))
	env.Define("string-append", NewBuiltin(builtinStringAppend))
	env.Define("string->list", NewBuiltin(builtinStringToList))
	env.Define("list->string", NewBuiltin(builtinListToString))
	env.Define("string-copy", NewBuiltin(builtinStringCopy))
	env.Define("string-fill!", NewBuiltin(builtinStringFill))

	// Add complex number procedures (R4RS section 6.5)
	env.Define("complex?", NewBuiltin(builtinComplexp))
	env.Define("real?", NewBuiltin(builtinRealp))
	env.Define("rational?", NewBuiltin(builtinRationalp))
	env.Define("integer?", NewBuiltin(builtinIntegerp))
	env.Define("make-rectangular", NewBuiltin(builtinMakeRectangular))
	env.Define("make-polar", NewBuiltin(builtinMakePolar))
	env.Define("real-part", NewBuiltin(builtinRealPart))
	env.Define("imag-part", NewBuiltin(builtinImagPart))
	env.Define("magnitude", NewBuiltin(builtinMagnitude))
	env.Define("angle", NewBuiltin(builtinAngle))

	// Add vector procedures (R4RS section 6.6)
	env.Define("vector?", NewBuiltin(builtinVectorp))
	env.Define("make-vector", NewBuiltin(builtinMakeVector))
	env.Define("vector", NewBuiltin(builtinVector))
	env.Define("vector-length", NewBuiltin(builtinVectorLength))
	env.Define("vector-ref", NewBuiltin(builtinVectorRef))
	env.Define("vector-set!", NewBuiltin(builtinVectorSet))
	env.Define("vector->list", NewBuiltin(builtinVectorToList))
	env.Define("list->vector", NewBuiltin(builtinListToVector))
	env.Define("vector-fill!", NewBuiltin(builtinVectorFill))

	return env
}

// Define binds a name to a value in the current environment
func (env *Environment) Define(name string, value *Value) {
	env.bindings[name] = value
}

// Set assigns a new value to an existing binding (searches up the scope chain)
func (env *Environment) Set(name string, value *Value) error {
	current := env
	for current != nil {
		if _, exists := current.bindings[name]; exists {
			current.bindings[name] = value
			return nil
		}
		current = current.parent
	}
	return fmt.Errorf("undefined variable: %s", name)
}

// Get retrieves a value by name (searches up the scope chain)
func (env *Environment) Get(name string) (*Value, error) {
	current := env
	for current != nil {
		if value, exists := current.bindings[name]; exists {
			return value, nil
		}
		current = current.parent
	}
	return nil, fmt.Errorf("undefined variable: %s", name)
}
